package com.yuanxin.chooseimage;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.media.ExifInterface;
import android.os.Environment;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.Target;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.sinooceanland.commonutils.LogUtil;
import com.yuanxin.chooseimage.customutil.LocalUtil;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import top.zibin.luban.CompressionPredicate;
import top.zibin.luban.Luban;
import top.zibin.luban.OnCompressListener;
import top.zibin.luban.OnRenameListener;


/**
 * Created by lemon on 2016/10/25.
 */

public class ReadImageDataManager extends ReactContextBaseJavaModule {
    public ReadImageDataManager(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    /**
     * @return the name of this module. This will be the name used to {@code require()} this module
     * from javascript.
     */
    @Override
    public String getName() {
        return "ReadImageDataManager";
    }

    @ReactMethod
    public void readImages(final ReadableArray fileArray, final Promise promise) {
        try {
            ImageBaseTask imageBaseTask = new ImageBaseTask(promise);
            imageBaseTask.execute(fileArray);
        } catch (Exception ex) {
            promise.reject("error", ex.getMessage());
        }
    }

    @ReactMethod
    public void readImage(final ReadableMap fileInfo, final Promise promise) {
        try {
            String filePath = fileInfo.getString("filePath");
            double imageWidth = -1;
            double imageHeight = -1;
            int scale = -1;
            int sill = 100;
            if (fileInfo.hasKey("width"))
                imageWidth = fileInfo.getDouble("width");
            if (fileInfo.hasKey("height"))
                imageWidth = fileInfo.getDouble("height");
            if (fileInfo.hasKey("scale"))
                scale = (int) (fileInfo.getDouble("scale") * 100);
            if (fileInfo.hasKey("sill"))//阀值 单位kb，如果文件大于sill，那么根据scale进行压缩，如果文件小于sill，则不压缩，默认值100kb
                sill = fileInfo.getInt("sill");
            WritableMap baseFile = Arguments.createMap();
            baseFile.putString("filePath", filePath);
            baseFile.putString("imageData", LocalUtil.getPirBase(filePath, imageWidth, imageHeight, scale, sill));
            promise.resolve(baseFile);
        } catch (Exception ex) {
            promise.reject("error", ex.getMessage());
        }
    }

    /**
     * 旋转角度缓存，避免同一个图片被频繁加入内存读取角度信息
     */
    private Map<String, Integer> degreeMap = new HashMap<>();

    /**
     * 读取照片exif信息中的旋转角度
     *
     * @return角度 获取从相册中选中图片的角度
     */
    @ReactMethod
    public void readPictureDegree(String path, Promise promise) {
        if (path == null || "".equals(path)) {
            promise.reject("error", "path is null");
            return;
        }
        //先在缓存中查找
        if (degreeMap.containsKey(path)) {
            promise.resolve(degreeMap.get(path));
        } else {//缓存没有，则正常读取，读取结果保存如缓存
            if (path.startsWith("http")) {
                try {
                    File file = Glide.with(getReactApplicationContext()).load(path).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get();
                    int degree = readPictureDegree(file.getAbsolutePath());
                    degreeMap.put(path, degree);
                    promise.resolve(degree);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    promise.reject(e);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                    promise.reject(e);
                }
            } else {
                //rn inmage组件的source.uri，带file://，所以需要删除这一部分，才可以正常找到文件
                path = path.replace("file://", "");
                int degree = readPictureDegree(path);
                degreeMap.put(path, degree);
                promise.resolve(degree);
            }
        }

    }

    private int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Log.d("ReadImageDataManager","degree : "+degree);
        return degree;
    }

    @ReactMethod
    public void compression(ReadableMap map, final Promise promise) {
        if (map == null) {
            promise.reject("error", "params is null!");
            return;
        }
        if (!map.hasKey("filePath")) {
            promise.reject("error", "filePath is null!");
            return;
        }
        final String filePath = map.getString("filePath");
        if (!map.hasKey("threshold")) {
            promise.reject("error", "ignoreBy is null!");
            return;
        }
        int threshold = map.getInt("threshold");

        Luban.with(getCurrentActivity())
                .load(filePath)
                .ignoreBy(threshold)
                .setTargetDir(getCurrentActivity().getCacheDir().getAbsolutePath())
                .setRenameListener(new OnRenameListener() {
                    @Override
                    public String rename(String filePath) {
                        String fileName = filePath.substring(filePath.lastIndexOf("/"));
                        return fileName.substring(0, fileName.lastIndexOf(".")) + "_compression_" + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."));
                    }
                })
                .filter(new CompressionPredicate() {
                    @Override
                    public boolean apply(String path) {
                        if (path == null || "".equals(path) || path.toLowerCase().endsWith(".gif"))
                            return false;
                        return true;
                    }
                })
                .setCompressListener(new OnCompressListener() {
                    @Override
                    public void onStart() {
                        // TODO 压缩开始前调用，可以在方法内启动 loading UI

                    }

                    @Override
                    public void onSuccess(File file) {
                        // TODO 压缩成功后调用，返回压缩后的图片文件
                        WritableMap map = Arguments.createMap();
                        map.putString("filePath", file.getPath());
//                         LogUtil.i("compression=filePath=" + file.getPath());
                        promise.resolve(map);
                    }

                    @Override
                    public void onError(Throwable e) {
                        // TODO 当压缩过程出现问题时调用
                        promise.reject("error", e.getMessage());
                    }
                }).launch();
    }


    /**
     * 锐化
     *
     * @param map
     * @param promise
     */
    @ReactMethod
    public void sharpen(ReadableMap map, Promise promise) {
        if (map == null) {
            promise.reject("error", "params is null!");
            return;
        }
        if (!map.hasKey("filePath")) {
            promise.reject("error", "filePath is null!");
            return;
        }
        String filePath = map.getString("filePath");
        Bitmap src = BitmapFactory.decodeFile(filePath, new BitmapFactory.Options());
        src = sharpenImageAmeliorate(src);
        String sharpenFilePath = filePath.substring(0, filePath.lastIndexOf(".")) + "_sharpen_" + System.currentTimeMillis() + filePath.substring(filePath.lastIndexOf("."));
        saveBitmap(sharpenFilePath, src);
        if (new File(sharpenFilePath).exists()) {
            WritableMap result = Arguments.createMap();
            result.putString("filePath", sharpenFilePath);
            promise.resolve(result);
        } else {
            promise.reject("error", "sharpen fail");
        }
    }

    public String saveBitmap(String cachePath, Bitmap b) {
        try {
            FileOutputStream fout = new FileOutputStream(cachePath);
            BufferedOutputStream bos = new BufferedOutputStream(fout);
            b.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
            bos.close();
            return cachePath;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }


    /**
     * 图片锐化（拉普拉斯变换）
     *
     * @param bmp
     * @return
     */
    public Bitmap sharpenImageAmeliorate(Bitmap bmp) {
        // 拉普拉斯矩阵
        int[] laplacian = new int[]{-1, -1, -1, -1, 9, -1, -1, -1, -1};
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.RGB_565);
        int pixR = 0;
        int pixG = 0;
        int pixB = 0;
        int pixColor = 0;
        int newR = 0;
        int newG = 0;
        int newB = 0;
        int idx = 0;
        float alpha = 0.3F;
        int[] pixels = new int[width * height];
        bmp.getPixels(pixels, 0, width, 0, 0, width, height);
        for (int i = 1, length = height - 1; i < length; i++) {
            for (int k = 1, len = width - 1; k < len; k++) {
                idx = 0;
                for (int m = -1; m <= 1; m++) {
                    for (int n = -1; n <= 1; n++) {
                        pixColor = pixels[(i + n) * width + k + m];
                        pixR = Color.red(pixColor);
                        pixG = Color.green(pixColor);
                        pixB = Color.blue(pixColor);
                        newR = newR + (int) (pixR * laplacian[idx] * alpha);
                        newG = newG + (int) (pixG * laplacian[idx] * alpha);
                        newB = newB + (int) (pixB * laplacian[idx] * alpha);
                        idx++;
                    }
                }
                newR = Math.min(255, Math.max(0, newR));
                newG = Math.min(255, Math.max(0, newG));
                newB = Math.min(255, Math.max(0, newB));
                pixels[i * width + k] = Color.argb(255, newR, newG, newB);
                newR = 0;
                newG = 0;
                newB = 0;
            }
        }
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    @ReactMethod
    public void contrast(ReadableMap map, Promise promise) {
        if (map == null) {
            promise.reject("error", "params is null!");
            return;
        }
        if (!map.hasKey("filePath")) {
            promise.reject("error", "filePath is null!");
            return;
        }
        String filePath = map.getString("filePath");
        Bitmap srcBitmap = BitmapFactory.decodeFile(filePath, new BitmapFactory.Options());

        int imgHeight = srcBitmap.getHeight();
        int imgWidth = srcBitmap.getWidth();

        Bitmap bmp = Bitmap.createBitmap(imgWidth, imgHeight,
                Bitmap.Config.ARGB_8888);
        float contrast = (float) ((127 + 64) / 128.0);
        ColorMatrix cMatrix = new ColorMatrix();
        cMatrix.set(new float[]{contrast, 0, 0, 0, 0, 0,
                contrast, 0, 0, 0,// 改变对比度
                0, 0, contrast, 0, 0, 0, 0, 0, 1, 0});

        Paint paint = new Paint();
        paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));

        Canvas canvas = new Canvas(bmp);
        // 在Canvas上绘制一个已经存在的Bitmap。这样，dstBitmap就和srcBitmap一摸一样了
        canvas.drawBitmap(srcBitmap, 0, 0, paint);

        String contrastFilePath = filePath.substring(0, filePath.lastIndexOf(".")) + "_contrast_" + System.currentTimeMillis() + filePath.substring(filePath.lastIndexOf("."));
        saveBitmap(contrastFilePath, bmp);
        if (new File(contrastFilePath).exists()) {
            WritableMap result = Arguments.createMap();
            result.putString("filePath", contrastFilePath);
            promise.resolve(result);
        } else {
            promise.reject("error", "contrast fail");
        }
    }

    @ReactMethod
    public void compressionVideo(ReadableMap map, final Promise promise) {
        String filePath = map.getString("filePath");
        WritableMap result = Arguments.createMap();
        result.putString("oupPath", filePath);
        promise.resolve(result);
    }

    private File getTempMovieDir() {
        File movie = new File(Environment.getExternalStorageDirectory().getPath(), "video");
        movie.mkdirs();
        return movie;
    }
}

